/**
 * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021. All rights reserved.
 * Description:
 */

#include "plugins/ecmascript/runtime/base/builtins_base.h"
#include "plugins/ecmascript/runtime/js_eval.h"
#include "plugins/ecmascript/runtime/js_function.h"
#include "plugins/ecmascript/runtime/js_async_generator_object.h"

namespace ark::ecmascript::builtins {
// 27.4.1.1 AsyncGeneratorFunction (p1, p2, ... , pn, body)
JSTaggedValue async_generator_function::AsyncGeneratorFunctionConstructor(EcmaRuntimeCallInfo *argv)
{
    return EvalUtils::CreateDynamicFunction(argv, EvalUtils::DynamicFunctionKind::ASYNC_GENERATOR);
}

// 27.6.1.2 AsyncGenerator.prototype.next(value)
JSTaggedValue async_generator::proto::Next(EcmaRuntimeCallInfo *argv)
{
    BUILTINS_API_TRACE(argv->GetThread(), AsyncGeneratorPrototype, Next);
    // 1.Let generator be the this value.
    JSThread *thread = argv->GetThread();
    [[maybe_unused]] EcmaHandleScope handleScope(thread);
    JSHandle<JSTaggedValue> generator = builtins_common::GetThis(argv);

    // 2. Let completion be NormalCompletion(value).
    JSHandle<JSTaggedValue> value = builtins_common::GetCallArg(argv, 0);
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<CompletionRecord> completionRecord = factory->NewCompletionRecord(CompletionRecord::NORMAL, value);

    // 3. Return ! AsyncGeneratorEnqueue(generator, completion, empty).
    JSHandle<JSTaggedValue> result = JSAsyncGeneratorObject::AsyncGeneratorEnqueue(thread, generator, completionRecord);
    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
    return result.GetTaggedValue();
}

// 27.6.1.3 AsyncGenerator.prototype.return(value)
JSTaggedValue async_generator::proto::Return(EcmaRuntimeCallInfo *argv)
{
    BUILTINS_API_TRACE(argv->GetThread(), AsyncGeneratorPrototype, Return);
    // 1.Let generator be the this value.
    JSThread *thread = argv->GetThread();
    [[maybe_unused]] EcmaHandleScope handleScope(thread);
    JSHandle<JSTaggedValue> generator = builtins_common::GetThis(argv);

    // 2. Let completion be Completion { [[Type]]: return, [[Value]]: value, [[Target]]: empty }.
    JSHandle<JSTaggedValue> value = builtins_common::GetCallArg(argv, 0);
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<CompletionRecord> completionRecord = factory->NewCompletionRecord(CompletionRecord::RETURN, value);

    // 3. Return ! AsyncGeneratorEnqueue(generator, completion, empty).
    JSHandle<JSTaggedValue> result = JSAsyncGeneratorObject::AsyncGeneratorEnqueue(thread, generator, completionRecord);
    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
    return result.GetTaggedValue();
}

// 27.6.1.4 AsyncGenerator.prototype.throw(exception)
JSTaggedValue async_generator::proto::Throw(EcmaRuntimeCallInfo *argv)
{
    BUILTINS_API_TRACE(argv->GetThread(), AsyncGeneratorPrototype, Throw);

    // 1.Let generator be the this value.
    JSThread *thread = argv->GetThread();
    [[maybe_unused]] EcmaHandleScope handleScope(thread);
    JSHandle<JSTaggedValue> generator = builtins_common::GetThis(argv);

    // 2. Let completion be ThrowCompletion(exception).
    JSHandle<JSTaggedValue> value = builtins_common::GetCallArg(argv, 0);
    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
    JSHandle<CompletionRecord> completionRecord = factory->NewCompletionRecord(CompletionRecord::THROW, value);

    // 3. Return ! AsyncGeneratorEnqueue(generator, completion, empty).
    JSHandle<JSTaggedValue> result = JSAsyncGeneratorObject::AsyncGeneratorEnqueue(thread, generator, completionRecord);
    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
    return result.GetTaggedValue();
}
}  // namespace ark::ecmascript::builtins
